#include "Parser.h"

/* Parser */
function initParser(char filename[])
{
    printf("Scanner\n");
    printf("*******\n");
    initSymTabStack();
    initScanner(filename);
    initCodeGenerator();
}

function simpleAllStars()
{
    mark("SimpleAllStars", 0);

    if(curKey.sym neq ENDF)
    {
        get();
        while(curKey.sym equ INVOL)
        {
            involve();
        }
        sequence();
        statementSequence();
    }
}

function statementSequence()
{
    while(curKey.sym equ IDENT or curKey.sym equ IF or curKey.sym equ WHILE or
          curKey.sym equ TYP or curKey.sym equ STRUCT or curKey.sym equ FUNC or curKey.sym equ CONST)
    {
        if(curKey.sym equ FUNC)
        {
            procedureDeclaration();
        }
        else
        {
            statement();
        }
        while (curKey.sym equ UNKN)
        {
            mark("Unknown symbol", 1);
            get();
        }

        if(curKey.sym equ ENDF)
        {
            mark("AWESOME JOB, MAN!!!", 0);
        }
    }
}

function statement()
{
    if(curKey.sym equ TYP or curKey.sym equ STRUCT or curKey.sym equ CONST)
    {
        declaration();
    }
    elif(curKey.sym equ WHILE)
    {
        whileStatement();
    }
    elif(curKey.sym equ IF)
    {
        ifStatement();
    }
    elif(curKey.sym equ IDENT)
    {
        get();
        if(curKey.sym equ LPAREN)
        {
            actualParameters();
        }
        else
        {
            selector();
            if(curKey.sym equ BECOME)
            {
                get();
                expression(NULL);
            }
        }
        if(curKey.sym equ COLON)
        {
            get();
        }
        else
        {
            mark("Semicolon expected", 1);
        }
    }
    else
    {
        mark("Statement expected", 1);
        get();
        statement();
    }
    mark("Statement successfully parsed", 0);
}

function procedureDeclaration()
{
    if(curKey.sym equ FUNC)
    {
        struct Object ptr funcObject = newObject;
        funcObject-> oClass = CLASSFUNC;
        get();
        if(curKey.sym equ IDENT)
        {
            funcObject-> name = getCurValue();

            struct Type ptr funcType = newType;
            funcType-> form = FORMFUNC;
            funcType-> fields = newSymTab;
            funcObject-> type = funcType;
            funcObject-> pointer = 0;

            initSubSymTab(funcType-> fields);

            get();
            if(curKey.sym equ LPAREN)
            {
                get();
                if(curKey.sym equ TYP or curKey.sym equ CONST)
                {
                    formalParameters(funcType-> fields);
                }
                if(curKey.sym equ RPAREN)
                {
                    get();
                    if(curKey.sym equ COLON)
                    {
                        newObj(funcObject);
                        get();
                    }
                    elif(curKey.sym equ LBRACE)
                    {
                        body();
                    }
                    else
                    {
                        mark("Semicolon or left brace expected", 1);
                    }
                }
                else
                {
                    mark("Right parentity expected", 1);
                }
            }
            else
            {
                mark("Left parentity expected", 1);
            }
        }
        else
        {
            mark("Identifier expected", 1);
        }
    }
    else
    {
        mark("Function expected", 1);
    }
    mark("Procedure successfully parsed", 0);
}

function body()
{
    if(curKey.sym equ LBRACE)
    {
        get();
        while(curKey.sym equ IDENT or curKey.sym equ IF or curKey.sym equ WHILE or
              curKey.sym equ TYP or curKey.sym equ STRUCT or curKey.sym equ CONST)
        {
            statement();
        }
        if(curKey.sym equ RBRACE)
        {
            get();
        }
        else
        {
            mark("Right brace expected(body)", 1);

        }
    }
    else
    {
        mark("Left brace expected", 1);

    }
    mark("Body successfully parsed", 0);
}

function formalParameters(struct SymTab ptr symTab)
{
    int constant;
    int pointer;
    struct Type ptr paramType = typ(&constant, &pointer);
    if(curKey.sym equ IDENT)
    {
        struct Object ptr object = newObject;
        object-> name = getCurValue();
        object-> oClass = CLASSVAR;
        object-> type = paramType;
        object-> pointer = pointer;

        if(constant > 0)
        {
            object-> oClass = CLASSCONST;
        }

        get();
        int array = 0;
        while(curKey.sym equ LBRAK)
        {
            get();
            if(curKey.sym equ RBRAK)
            {
                array = array + 1;
                get();
            }
            else
            {
                mark("Right bracket expected", 1);
            }
        }
        addObj(symTab, object);
        if(curKey.sym equ COMMA)
        {
            get();
            formalParameters(symTab);
        }
    }
    else
    {
        mark("Identifier expected", 1);
    }
    mark("Formal parameters successfully parsed", 0);
}

function declaration()
{
    if(curKey.sym equ STRUCT)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            char ptr structIdent = getCurValue();
            get();
            if(curKey.sym equ PTR)
            {
                int pointer = 0;
                while(curKey.sym equ PTR)
                {
                    pointer = pointer + 1;
                    get();
                }
                struct Object ptr found = search(structIdent);
                if(found neq NULL and curKey.sym equ IDENT)
                {
                    identList(found-> type, 0, pointer);
                    if(curKey.sym equ BECOME)
                    {
                        get();
                        expression(NULL);
                    }
                }
                else
                {
                    mark("Identifier expected", 1);
                }
            }
            elif(curKey.sym equ LBRACE)
            {
                /*
                * Erzeugt ein neues Object
                */
                struct Object ptr structObj = newObject;
                structObj-> name = structIdent;
                structObj-> oClass = CLASSSTRUCT;

                struct Type ptr structType = newType;
                structType-> form = FORMSTRUCT;
                structType-> fields = newSymTab;
                initSubSymTab(structType-> fields);
                structObj-> type = structType;
                newObj(structObj);

                get();
                while(curKey.sym equ TYP or curKey.sym equ STRUCT)
                {
                    fieldDeclaration(structType-> fields);
                }
                if(curKey.sym equ RBRACE)
                {
                    get();
                }
                else
                {
                    mark("Right brace expected (struct type)", 1);
                }
            }
            elif(curKey.sym equ IDENT)
            {
                struct Object ptr found = search(structIdent);
                if(found neq NULL)
                {
                    identList(found-> type, 0, 0);
                    if(curKey.sym equ BECOME)
                    {
                        get();
                        expression(NULL);
                    }
                }
                else
                {
                    mark("Struct is unknown", 1);
                }
            }
            else
            {
                mark("Pointer or Identifier expected", 1);

            }
        }
        else
        {
            mark("Identifier expected", 1);

        }
    }
    elif(curKey.sym equ TYP or curKey.sym equ CONST)
    {
        int constant = 0;
        if(curKey.sym equ CONST)
        {
            constant = 1;
            get();
        }
        if(curKey.sym equ TYP)
        {
            struct Type ptr baseType;
            char ptr typus = getCurValue();
            if(strcmp(typus, "int") equ 0)
            {
                baseType = intType;
            }
            elif(strcmp(typus, "bool") equ 0)
            {
                baseType = boolType;
            }
            elif(strcmp(typus, "char") equ 0)
            {
                baseType = charType;
            }
            else
            {
                mark("This kind of basic type is unknown", 1);
            }

            int pointer = 0;
            get();
            while(curKey.sym equ PTR)
            {
                pointer = pointer + 1;
                get();
            }
            identList(baseType, constant, pointer);
            if(curKey.sym equ BECOME)
            {
                get();
                expression(NULL);
            }
        }
        else
        {
            mark("Type expected", 1);
        }
    }
    else
    {
        mark("Type or Struct expected", 1);
    }
    if(curKey.sym equ COLON)
    {
        get();
    }
    else
    {
        mark("Semicolon expected", 1);

    }
    mark("Declaration successfully parsed", 0);
}

function fieldDeclaration(struct SymTab ptr symTab)
{
    //FieldType
    struct Type ptr fieldType;
    if(curKey.sym equ TYP)
    {
        char ptr typus = getCurValue();
        if(strcmp(typus, "int") equ 0)
        {
            fieldType = intType;
        }
        elif(strcmp(typus, "bool") equ 0)
        {
            fieldType = boolType;
        }
        elif(strcmp(typus, "char") equ 0)
        {
            fieldType = charType;
        }
        else
        {
            mark("This kind of basic type is unknown", 1);
        }
        get();
    }
    elif(curKey.sym equ STRUCT)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            struct Object ptr found = search(getCurValue());
            if(found neq NULL and found-> oClass equ CLASSSTRUCT)
            {
                fieldType = found-> type;
            }
            else
            {
                mark("Struct is unknown", 1);
            }
            get();
        }
        else
        {
            mark("Identifier expected", 1);
        }
    }
    else
    {
        mark("Struct or Type expected", 1);
    }
    int pointer = 0;
    while(curKey.sym equ PTR)
    {
        pointer = pointer + 1;
        get();
    }
    fieldIdentList(fieldType, symTab, pointer);
    if(curKey.sym equ COLON)
    {
        get();
    }
    else
    {
        mark("Semicolon expected", 1);

    }
    mark("FieldType successfully parsed", 0);
}

struct Type ptr typ(int ptr constant, int ptr pointer)
{
    struct Type ptr type;
    constant = 0;
    if(curKey.sym equ CONST)
    {
        constant = (int ptr) 1;
        get();
    }
    if(curKey.sym equ TYP)
    {
        char ptr typus = getCurValue();
        if(strcmp(typus, "int") equ 0)
        {
            type = intType;
        }
        elif(strcmp(typus, "bool") equ 0)
        {
            type = boolType;
        }
        elif(strcmp(typus, "char") equ 0)
        {
            type = charType;
        }
        else
        {
            mark("This kind of basic type is unknown", 1);
        }
        get();
    }
    elif(curKey.sym equ STRUCT)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            struct Object ptr found = search(getCurValue());
            if(found neq NULL and found-> oClass equ CLASSSTRUCT)
            {
                type = found-> type;
            }
            else
            {
                mark("Struct is unknown", 1);
            }
            get();
        }
        else
        {
            mark("Identifier expected", 1);
        }
    }
    else
    {
        mark("Type or struct expected", 1);
    }
    pointer = 0;
    while(curKey.sym equ PTR)
    {
        pointer = pointer + 1;
        get();
    }
    mark("Type successfully parsed", 0);

    return type;
}

function fieldIdentList(struct Type ptr type, struct SymTab ptr symTab, int pointer)
{
    if(curKey.sym equ IDENT)
    {
        char ptr identName = getCurValue();
        struct Object ptr object = newObject;
        object-> name = identName;
        object-> type = type;
        object-> oClass = CLASSVAR;
        object-> pointer = pointer;

        get();
        int array = 0;
        while(curKey.sym equ LBRAK)
        {
            get();
            if(curKey.sym equ RBRAK)
            {
                array = array + 1;
                get();
            }
            else
            {
                expression(NULL);
                if(curKey.sym equ RBRAK)
                {
                    array = array + 1;
                    get();
                }
                else
                {
                    mark("Right bracket expected", 1);
                }
            }
        }

        if(array > 0)
        {
            struct Type ptr arrayType = newType;
            arrayType-> form = FORMARRAY;
            arrayType-> len = 10;
            arrayType-> base = type;

            object-> type = arrayType;
        }

        addObj(symTab, object);
        if(curKey.sym equ COMMA)
        {
            get();
            fieldIdentList(type, symTab, pointer);
        }
    }
    else
    {
        mark("Identifier expected", 1);

    }
    mark("Identlist successfully parsed", 0);
}

function identList(struct Type ptr type, int constant, int pointer)
{
    if(curKey.sym equ IDENT)
    {
        char ptr identName = getCurValue();
        struct Object ptr object = newObject;
        object-> name = identName;
        object-> type = type;
        object-> oClass = CLASSVAR;
        if(constant equ 1)
        {
            object-> oClass = CLASSCONST;
        }
        object-> pointer = pointer;

        get();
        int array = 0;
        while(curKey.sym equ LBRAK)
        {
            get();
            if(curKey.sym equ RBRAK)
            {
                array = array + 1;
                get();
            }
            else
            {
                expression(NULL);
                if(curKey.sym equ RBRAK)
                {
                    array = array + 1;
                    get();
                }
                else
                {
                    mark("Right bracket expected", 1);
                }
            }
        }

        if(array > 0)
        {
            struct Type ptr arrayType = newType;
            arrayType-> form = FORMARRAY;
            arrayType-> len = 10;
            arrayType-> base = type;

            object-> type = arrayType;
        }
        newObj(object);

        if(curKey.sym equ COMMA)
        {
            get();
            identList(type, constant, pointer);
        }
    }
    else
    {
        mark("Identifier expected", 1);

    }
    mark("Identlist successfully parsed", 0);
}

//expression = simpleExpression [( "equ" | "neq" | "<" | ">" | "<=" | ">=") simpleExpression].
function expression(struct Item ptr result)
{
    simpleExpression();
    if(curKey.sym equ EQL or curKey.sym equ NEQ or curKey.sym equ LSS or
       curKey.sym equ GRT or curKey.sym equ LEQ or curKey.sym equ GEQ)
    {
        get();
        simpleExpression();
    }
    mark("Expression successfully parsed", 0);
}

function simpleExpression()
{
    if(curKey.sym equ PLUS or curKey.sym equ MINUS)
    {
        get();
    }
    term();
    while(curKey.sym equ PLUS or curKey.sym equ MINUS or curKey.sym equ OR)
    {
        get();
        term();
    }
    mark("Simple Expression successfully parsed", 0);
}

function term()
{
    factor();
    while(curKey.sym equ MOD or curKey.sym equ TIMES or curKey.sym equ DIV or curKey.sym equ AND)
    {
        get();
        factor();
    }
    mark("Term successfully Parsed", 0);
}

function factor()
{
    if(curKey.sym equ IDENT)
    {
        get();
        selector();
    }
    elif(curKey.sym equ NUMBER)
    {
        get();
    }
    elif(curKey.sym equ CHAR)
    {
        get();
    }
    elif(curKey.sym equ LPAREN)
    {
        get();
        expression(NULL);
        if(curKey.sym equ RPAREN)
        {
            get();
        }
        else
        {
            mark("Right parentity expected", 1);

        }
    }
    elif(curKey.sym equ STRING)
    {
        get();
    }
    else
    {
        mark("Factor expected", 1);

    }
    mark("Factor successfully Parsed", 0);
}

function selector()
{
    while(curKey.sym equ PERIOD or curKey.sym equ LBRAK or curKey.sym equ ARROW)
    {
        if(curKey.sym equ PERIOD or curKey.sym equ ARROW)
        {
            get();
            if(curKey.sym neq IDENT)
            {
                mark("Identifier expected(Selector)", 1);

            }
            else
            {
                get();
            }
        }
        elif(curKey.sym equ LBRAK)
        {
            get();
            expression(NULL);
            if(curKey.sym neq RBRAK)
            {
                mark("Left bracket expected", 1);

            }
            else
            {
                get();
            }
        }
    }
    mark("Selector successfully parsed", 0);
}

function ifStatement()
{
    if(curKey.sym equ IF)
    {
        get();
        if(curKey.sym equ LPAREN)
        {
            get();
            expression(NULL);
            if(curKey.sym equ RPAREN)
            {
                get();
                if(curKey.sym equ LBRACE)
                {
                    get();
                    statementSequence();
                    if(curKey.sym equ RBRACE)
                    {
                        get();
                        while(curKey.sym equ ELIF)
                        {
                            get();
                            if(curKey.sym equ LPAREN)
                            {
                                get();
                                expression(NULL);
                                if(curKey.sym equ RPAREN)
                                {
                                    get();
                                    if(curKey.sym equ LBRACE)
                                    {
                                        get();
                                        statementSequence();
                                        if(curKey.sym equ RBRACE)
                                        {
                                            get();
                                        }
                                        else
                                        {
                                            mark("Right brace expected", 1);

                                        }
                                    }
                                    else
                                    {
                                        mark("Left brace expected", 1);

                                    }
                                }
                                else
                                {
                                    mark("Right parentity expected", 1);

                                }
                            }
                            else
                            {
                                mark("Left parentity expected", 1);

                            }
                        }
                        if(curKey.sym equ ELSE)
                        {
                            get();
                            if(curKey.sym equ LBRACE)
                            {
                                get();
                                statementSequence();
                                if(curKey.sym equ RBRACE)
                                {
                                    get();
                                }
                                else
                                {
                                    mark("Right brace expected", 1);

                                }
                            }
                            else
                            {
                                mark("Left brace expected", 1);

                            }
                        }
                    }
                    else
                    {
                        mark("Right brace expected", 1);

                    }
                }
                else
                {
                    mark("Left brace expected", 1);

                }
            }
            else
            {
                mark("Right parentity expected", 1);
            }
        }
        else
        {
            mark("Left parentity expected", 1);

        }
    }
    else
    {
        mark("if expected", 1);
    }
    mark("If statement successfully parsed", 0);
}

function whileStatement()
{
    if(curKey.sym equ WHILE)
    {
        get();
        if(curKey.sym equ LPAREN)
        {
            get();
            expression(NULL);
            if(curKey.sym equ RPAREN)
            {
                get();
                if(curKey.sym equ LBRACE)
                {
                    get();
                    statementSequence();
                    if(curKey.sym equ RBRACE)
                    {
                        get();
                    }
                    else
                    {
                        mark("Right brace expected", 1);

                    }
                }
                else
                {
                    mark("Left brace expected", 1);

                }
            }
            else
            {
                mark("Right parentity expected", 1);

            }
        }
        else
        {
            mark("Left parentity expected", 1);

        }
    }
    else
    {
        mark("while expected", 1);

    }
    mark("While statement successfully parsed", 0);
}

function actualParameters()
{
    if(curKey.sym equ LPAREN)
    {
        get();
        if(curKey.sym equ RPAREN)
        {
            get();
        }
        else
        {
            expression(NULL);
            while(curKey.sym equ COMMA)
            {
                get();
                expression(NULL);
            }
            if(curKey.sym neq RPAREN)
            {
                mark("Right parentity expected", 1);
            }
            else
            {
                get();
            }
        }
    }
    mark("ActualParameters successfully parsed", 0);
}

function sequenceSelector()
{
    while(curKey.sym equ PERIOD)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            get();
        }
        else
        {
            mark("Identifier expected", 1);

        }
    }
}

function sequence()
{
    if(curKey.sym equ SEQ)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            get();
            sequenceSelector();
            if(curKey.sym equ COLON)
            {
                get();
            }
            else
            {
                mark("semicolon expected", 1);

            }
        }
        else
        {
            mark("identifier expected", 1);

        }
    }
    else
    {
        mark("sequence expected", 1);

    }
    mark("Sequence successfully parsed", 0);
}

function involve()
{
    if(curKey.sym equ INVOL)
    {
        get();
        if(curKey.sym equ IDENT)
        {
            get();
            sequenceSelector();
            if(curKey.sym equ COLON)
            {
                get();
            }
            else
            {
                mark("semicolon expected", 1);

            }
        }
        else
        {
            mark("identifier expected", 1);

        }
    }
    else
    {
        mark("involve expected", 1);

    }
    mark("Involve successfully parsed", 0);
}

function clearParser()
{
    clearScanner();
    clearSymTabStack();
}
